/*!
 * Ext JS Library 3.2.0
 * Copyright(c) 2006-2010 Ext JS, Inc.
 * licensing@extjs.com
 * http://www.extjs.com/license
 */
/**
 * @class Ext.ux.ToolbarDroppable
 * @extends Object
 * Plugin which allows items to be dropped onto a toolbar and be turned into new Toolbar items.
 * To use the plugin, you just need to provide a createItem implementation that takes the drop
 * data as an argument and returns an object that can be placed onto the toolbar. Example:
 * <pre>
 * new Ext.ux.ToolbarDroppable({
 *   createItem: function (data) {
 *     return new Ext.Button({text: data.text});
 *   }
 * });
 * </pre>
 * The afterLayout function can also be overridden, and is called after a new item has been 
 * created and inserted into the Toolbar. Use this for any logic that needs to be run after
 * the item has been created.
 */
Ext.ux.ToolbarDroppable = Ext.extend(Object, {
    /**
     * @constructor
     */
    constructor: function (config) {
      Ext.apply(this, config, {
          
      });
    },
    
    /**
     * Initializes the plugin and saves a reference to the toolbar
     * @param {Ext.Toolbar} toolbar The toolbar instance
     */
    init: function (toolbar) {
      /**
       * @property toolbar
       * @type Ext.Toolbar
       * The toolbar instance that this plugin is tied to
       */
      this.toolbar = toolbar;
      
      this.toolbar.on({
          scope : this,
          render: this.createDropTarget
      });
    },
    
    /**
     * Creates a drop target on the toolbar
     */
    createDropTarget: function () {
        /**
         * @property dropTarget
         * @type Ext.dd.DropTarget
         * The drop target attached to the toolbar instance
         */
        this.dropTarget = new Ext.dd.DropTarget(this.toolbar.getEl(), {
            notifyOver: this.notifyOver.createDelegate(this),
            notifyDrop: this.notifyDrop.createDelegate(this)
        });
    },
    
    /**
     * Adds the given DD Group to the drop target
     * @param {String} ddGroup The DD Group
     */
    addDDGroup: function (ddGroup) {
        this.dropTarget.addToGroup(ddGroup);
    },
    
    /**
     * Calculates the location on the toolbar to create the new sorter button based on the XY of the
     * drag event
     * @param {Ext.EventObject} e The event object
     * @return {Number} The index at which to insert the new button
     */
    calculateEntryIndex: function (e) {
        var entryIndex = 0,
            toolbar    = this.toolbar,
            items      = toolbar.items.items,
            count      = items.length,
            xTotal     = toolbar.getEl().getXY()[0],
            xHover     = e.getXY()[0] - xTotal;
        
        for (var index = 0; index < count; index++) {
            var item     = items[index],
                width    = item.getEl().getWidth(),
                midpoint = xTotal + width / 2;
            
            xTotal += width;
            
            if (xHover < midpoint) {
                entryIndex = index;       

                break;
            } else {
                entryIndex = index + 1;
            }
        }
        
        return entryIndex;
    },
    
    /**
     * Returns true if the drop is allowed on the drop target. This function can be overridden
     * and defaults to simply return true
     * @param {Object} data Arbitrary data from the drag source
     * @return {Boolean} True if the drop is allowed
     */
    canDrop: function (data) {
        return true;
    },
    
    /**
     * Custom notifyOver method which will be used in the plugin's internal DropTarget
     * @return {String} The CSS class to add
     */
    notifyOver: function (dragSource, event, data) {
        return this.canDrop.apply(this, arguments) ? this.dropTarget.dropAllowed : this.dropTarget.dropNotAllowed;
    },
    
    beforeRemoteCreate : Ext.emptyFn,
    afterRemoteCreate : Ext.emptyFn,
    
    /**
     * Called when the drop has been made. Creates the new toolbar item, places it at the correct location
     * and calls the afterLayout callback.
     */
    notifyDrop: function (dragSource, event, data) {
        var canAdd = this.canDrop(dragSource, event, data),
            tbar   = this.toolbar;
        
        if (canAdd) {
            var entryIndex = this.calculateEntryIndex(event);
            
            if (this.mode === "remote") {
                var remoteOptions = {index : entryIndex},
                    dc = this.directEventConfig || {},
                    loadingItem;
                    
                if (this.beforeRemoteCreate({
                    data : data, 
                    options : remoteOptions,
                    dragSource : dragSource, 
                    event : event
                }) === false) {
                    return false;
                }
                
                loadingItem = new Ext.Toolbar.TextItem({
                    text : "<div class='loading-indicator'>&nbsp;</div>"                    
                });
                tbar.insert(entryIndex, loadingItem); 
                
                dc.userSuccess = this.remoteCreateSuccess.createDelegate(this);
                dc.userFailure = this.remoteCreateFailure.createDelegate(this);
                dc.extraParams = remoteOptions;
                dc.control = this;
                dc.entryIndex = entryIndex;
                dc.loadingItem = loadingItem;
                dc.eventType = "postback";
                dc.action = "create";
                
                Ext.net.DirectEvent.request(dc);
            }
            else {
                tbar.insert(entryIndex, this.createItem(data));                
            }
            
            tbar.doLayout();            
            this.afterLayout();
        }
        
        return canAdd;
    },
    
    remoteCreateSuccess : function (response, result, context, type, action, extraParams, o) {
        this.toolbar.remove(o.loadingItem);
        
        var rParams;
		
		try {
			rParams = result.extraParamsResponse || {};
			var responseObj = result.serviceResponse;
            result = { success: responseObj.success, msg: responseObj.message };            
		} catch (ex) {
		    result.success = false;
		    result.msg = ex.message;
		}
		
		if (result.success !== true) {
			this.afterRemoteCreate({
		        success : false,
		        message : result.msg,
		        response : response, 
		        o : o
		    });
		    this.toolbar.doLayout();			
			return;
		}
		
		this.toolbar.insert(Ext.isDefined(rParams.index) ? rParams.ra_index : o.entryIndex, Ext.decode(rParams.ra_item)); 
		
		this.toolbar.doLayout();
    },
    
    remoteCreateFailure : function (response, result, context, type, action, extraParams, o) {
        this.toolbar.remove(o.loadingItem);
        this.afterRemoteCreate({
	        success : false,
	        message : response.responseText,
	        response : response, 
	        o : o
	    });
	    this.toolbar.doLayout();	
    },
    
    /**
     * Creates the new toolbar item based on drop data. This method must be implemented by the plugin instance
     * @param {Object} data Arbitrary data from the drop
     * @return {Mixed} An item that can be added to a toolbar
     */
    createItem: function (data) {
        throw new Error("The createItem method must be implemented in the ToolbarDroppable plugin");
    },
    
    /**
     * Called after a new button has been created and added to the toolbar. Add any required cleanup logic here
     */
    afterLayout: Ext.emptyFn
});

Ext.net.ResourceMgr.notifyScriptLoaded();